package com.flying.flow.model;

import java.util.Date;
import java.util.List;

import com.flying.common.util.Codes;
import com.flying.common.util.Utils;
import com.flying.flow.model.Node.EmergencyLevel;
import com.flying.flow.model.Node.PriorityLevel;
import com.flying.flow.model.NodeInstance.NodeInstanceStatus;
import com.flying.flow.model.Task.TaskStatus;
import com.flying.framework.annotation.ConstantEnum;
import com.flying.framework.annotation.Param;
import com.flying.framework.annotation.Property;
import com.flying.framework.annotation.ServiceField;
import com.flying.framework.annotation.ServiceFieldParam;
import com.flying.framework.data.Data;
import com.flying.framework.data.DataSerializable;
import com.flying.framework.metadata.Meta;

@SuppressWarnings("serial")
@Meta(id="f_flow_instance",title="流程实例", table="f_flow_instance", primaryKeys={"flow_instance_id"})
public class FlowInstance extends Data implements DataSerializable {
	public final static String ENTITY_NAME = "f_flow_instance";

	public final static String FLOW_INSTANCE_ID = "flow_instance_id";
	public final static String FLOW_DEF_ID = "flow_def_id";
	public final static String FLOW_ID = "flow_id";
	public final static String NAME = "name";
	public final static String REMARKS = "remarks";
	public final static String ORDER_NO = "order_no";
	public final static String ORG_CODE = "org_code";
	public final static String BUSINESS_TYPE = "business_type";
	public final static String BUSINESS_CODE = "business_code";
	public final static String STATUS = "status";
	public final static String PRIORITY_LEVEL = "priority_level";
	public final static String EMERGENCY_LEVEL = "emergency_level";
	public final static String START_TIME = "start_time";
	public final static String FINISH_TIME = "finish_time";
	public final static String CONSUME_SECONDS = "consume_seconds";
	public final static String CREATOR = "creator";
	public final static String CREATE_TIME = "create_time";
	public final static String UPDATOR = "updator";
	public final static String UPDATE_TIME = "update_time";
	
	public enum FlowInstanceStatus implements ConstantEnum<Integer> {
		CREATED(0, "未开始"), PROCESSING(1, "处理中"), SUCCESS(2, "成功结束"), FAIL(3, "异常结束");
		
		public final int type;
		public final String remarks;
		
		FlowInstanceStatus(int type, String remarks) {
			this.type = type;
			this.remarks = remarks;
		}
		@Override
		public Integer value() {
			return type;
		}
		@Override
		public String text() {
			return remarks;
		}
	}

	
	@Param(value=FLOW_INSTANCE_ID,   required=true,   desc="流程实例ID" , generator=Codes.AUTO_INCREMENT, 
			props= {@Property(name="type",value="hidden")})
	private Long flowInstanceId;
	
	@Param(value=FLOW_DEF_ID,   required=true,   desc="流程定义ID" , 
			props= {@Property(name="type",value="hidden")})
	private Long flowDefId;
	
	@Param(value=FLOW_ID,   required=true,   desc="流程ID" , 
			props= {@Property(name="type",value="hidden")})
	private Long flowId;
	
	@Param(value=NAME,   required=true,   maxlength=100,	desc="名称",
			props= {@Property(name="condition",value="true")})
	private String name;
	
	@Param(value=REMARKS,   required=false,   maxlength=1000,	desc="说明" )
	private String remarks;
	
	@Param(value=ORDER_NO,   required=false,   maxlength=40,	desc="工单号" )
	private String orderNo;
	
	@Param(value=ORG_CODE,   required=false,   maxlength=10,	desc="机构代码" ,
			props= {@Property(name="condition",value="true")})
	private String orgCode;
	
	@Param(value=BUSINESS_TYPE,   required=false,   maxlength=10,	desc="业务类型" ,
			props= {@Property(name="condition",value="true"), 
					@Property(name="type",value="combobox"), 
					@Property(name="valueField",value="business_type"), 
					@Property(name="textField",value="name"), 
					@Property(name="url",value="/flow/FlowService/findAll.do?$value=rows")})
	private String businessType;
	
	@Param(value=BUSINESS_CODE,   required=false,   maxlength=10,	desc="业务代码" ,
			props= {@Property(name="condition",value="true")})
	private String businessCode;
	
	@Param(value=STATUS,   required=false,   enumClass=FlowInstanceStatus.class,	desc="状态" ,
			props= {@Property(name="condition",value="true"), 
					@Property(name="type",value="combobox"), 
					@Property(name="valueField",value="value"), 
					@Property(name="textField",value="text"), 
					@Property(name="url",value="/flow/enums/findEnums.do?$value=rows&class=com.flying.flow.model.FlowInstance$FlowInstanceStatus")})
	private Integer status;
	
	@Param(value=PRIORITY_LEVEL,   required=false,   enumClass = PriorityLevel.class,	desc="优先级别" ,
			props= {@Property(name="condition",value="true"), 
					@Property(name="type",value="combobox"), 
					@Property(name="valueField",value="value"), 
					@Property(name="textField",value="text"), 
					@Property(name="url",value="/flow/enums/findEnums.do?$value=rows&class=com.flying.flow.model.Node$PriorityLevel")} )
	private Integer priorityLevel;
	
	@Param(value=EMERGENCY_LEVEL,   required=false,   enumClass = EmergencyLevel.class,	desc="紧急程度",
			props= {@Property(name="condition",value="true"), 
					@Property(name="type",value="combobox"), 
					@Property(name="valueField",value="value"), 
					@Property(name="textField",value="text"), 
					@Property(name="url",value="/flow/enums/findEnums.do?$value=rows&class=com.flying.flow.model.Node$EmergencyLevel")} )
	private Integer emergencyLevel;
	
	@Param(value=START_TIME,   required=false,   desc="开始时间" )
	private Date startTime;
	
	@Param(value=FINISH_TIME,   required=false,   desc="结束时间" )
	private Date finishTime;
	
	@Param(value=CONSUME_SECONDS,   required=false,   desc="任务耗时" )
	private Integer consumeSeconds;
	
	@Param(value=CREATE_TIME,   required=false,   desc="创建时间" )
	private Date createTime;
	
	@Param(value=CREATOR,   required=false,   maxlength=100,	desc="创建人" )
	private String creator;
	
	@Param(value=UPDATE_TIME,   required=false,   desc="完成时间" )
	private Date updateTime;
	
	@Param(value=UPDATOR,   required=false,   maxlength=100,	desc="修改人" )
	private String updator;

	@ServiceField(serviceId="NodeInstanceService:findByFlowInstanceId", lazyLoad=false, valueAttribute="rows", 
			params={@ServiceFieldParam(param=NodeInstance.FLOW_INSTANCE_ID, value="$"+FLOW_INSTANCE_ID), @ServiceFieldParam(param=NodeInstance.STATUS, value="2")})
	@Param(value="nodeInstances",   required=false,   desc="流程节点实例", ignored=true )
	private List<NodeInstance> nodeInstances;

	@ServiceField(serviceId="TaskService:findByFlowInstanceId", lazyLoad=false, valueAttribute="rows", 
			params={@ServiceFieldParam(param=NodeInstance.FLOW_INSTANCE_ID, value="$"+FLOW_INSTANCE_ID)})
	@Param(value="tasks",   required=false,   desc="流程任务", ignored=true )
	private List<Task> tasks;
	
	public String getOrgCode() {
		return orgCode;
	}

	public void setOrgCode(String orgCode) {
		this.orgCode = orgCode;
	}
	
	public Date getCreateTime() {
		return this.createTime;
	}
	
	public void setCreateTime(Date createTime) {
		this.createTime = createTime;
	}
	
	public Date getStartTime() {
		return startTime;
	}

	public void setStartTime(Date startTime) {
		this.startTime = startTime;
	}

	public Date getFinishTime() {
		return finishTime;
	}

	public void setFinishTime(Date finishTime) {
		this.finishTime = finishTime;
	}

	public Integer getConsumeSeconds() {
		return consumeSeconds;
	}

	public void setConsumeSeconds(Integer consumeSeconds) {
		this.consumeSeconds = consumeSeconds;
	}

	public String getCreator() {
		return this.creator;
	}
	
	public void setCreator(String creator) {
		this.creator = creator;
	}
	
	public Long getFlowDefId() {
		return this.flowDefId;
	}
	
	public void setFlowDefId(Long flowDefId) {
		this.flowDefId = flowDefId;
	}
	
	public Long getFlowId() {
		return this.flowId;
	}
	
	public void setFlowId(Long flowId) {
		this.flowId = flowId;
	}
	
	public Long getFlowInstanceId() {
		return this.flowInstanceId;
	}
	
	public void setFlowInstanceId(Long flowInstanceId) {
		this.flowInstanceId = flowInstanceId;
	}
	
	public String getName() {
		return this.name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getRemarks() {
		return this.remarks;
	}
	
	public void setRemarks(String remarks) {
		this.remarks = remarks;
	}
	
	public String getOrderNo() {
		return orderNo;
	}

	public void setOrderNo(String orderNo) {
		this.orderNo = orderNo;
	}

	public Integer getPriorityLevel() {
		return priorityLevel;
	}

	public void setPriorityLevel(Integer priorityLevel) {
		this.priorityLevel = priorityLevel;
	}

	public Integer getEmergencyLevel() {
		return emergencyLevel;
	}

	public void setEmergencyLevel(Integer emergencyLevel) {
		this.emergencyLevel = emergencyLevel;
	}

	public Integer getStatus() {
		return this.status;
	}
	
	public void setStatus(Integer status) {
		this.status = status;
	}
	
	public String getBusinessType() {
		return businessType;
	}

	public void setBusinessType(String businessType) {
		this.businessType = businessType;
	}

	public String getBusinessCode() {
		return businessCode;
	}

	public void setBusinessCode(String businessCode) {
		this.businessCode = businessCode;
	}

	public Date getUpdateTime() {
		return this.updateTime;
	}
	
	public void setUpdateTime(Date updateTime) {
		this.updateTime = updateTime;
	}
	
	public String getUpdator() {
		return this.updator;
	}
	
	public void setUpdator(String updator) {
		this.updator = updator;
	}

	public List<NodeInstance> getNodeInstances() {
		return nodeInstances;
	}

	public void setNodeInstances(List<NodeInstance> nodeInstances) {
		this.nodeInstances = nodeInstances;
	}

	public List<Task> getTasks() {
		return tasks;
	}

	public void setTasks(List<Task> tasks) {
		this.tasks = tasks;
	}
	
	public List<String> getCurrentNodeNames() {
		List<String> res = Utils.newArrayList();
		if(this.getStatus() <= FlowInstanceStatus.PROCESSING.value()) {
			List<NodeInstance> l = this.getNodeInstances();
			l.stream().filter(x -> x.getStatus() == NodeInstanceStatus.PROCESSING.value()).
			forEach(x -> {
				res.add(x.getName());
			});
		}
		return res;
	}
	
	public List<String> getCurrentParticipantIds() {
		List<String> res = Utils.newArrayList();
		if(this.getStatus() <= FlowInstanceStatus.PROCESSING.value()) {
			List<Task> l = this.getTasks();
			l.stream().filter(x -> (x.getStatus() == TaskStatus.ASSIGNED.value() || x.getStatus() == TaskStatus.PROCESSING.value())).
			forEach(x -> {
				res.add(x.getParticipantId());
			});
		}
		return res;
	}
	
}